﻿#ifndef __AVOID_CONTROL_LIST_HEAD_FILE_INCLUEDD__
#define __AVOID_CONTROL_LIST_HEAD_FILE_INCLUEDD__
#include "ctlSingleLabel.h"
#include "ctlSingleEdit.h"
#include "ctlButton.h"
#include "ctlScroll.h"
#include "interface/IFont.h"
#include "interface/IBackground.h"
#include <vector>

namespace swui
{
	struct ctlNotifyList
	{
		enum { insertRow, insertColumn, 
			removeRow, removeColumn,
			afterInsertRow, afterInsertColumn, 
			afterRemoveRow, afterRemoveColumn,
			/* 下面这个事件用来在重绘时修改控件外观
			 * 也只应该在这个事件里面来修改 */
			redrawRow
		} state;
		/* 对于前面四个事件，那么表示是否允许插入或删除
		  * 对于 redrawRow，那么表示是否在返回之后设置选中的样式 */
		bool* isAllow;	
		unsigned index;
		/* 这个值仅仅在 afterInsertRow 和 redrawRow 不为 nullptr
		 * 并且无论如何绝对不要手动修改 ctrl 的位置 */
		ctlStatic* ctrl;	
		/* 对于 insertRow 和 insertColumn
		 * 可以修改下面的值来修改宽度（高度） 
		 * 对于其它事件，length 为 nullptr */
		unsigned *length;
	};
	struct ctlNotifyListEdit
	{
		enum { before, after } state;
		/* 如果是 before，那么这个值决定是否开始编辑
		 * 如果是 after，那么这个值决定是否设置编辑框的文字 */
		bool* isAllow;
		/* 对于 before 无用
		 * 对于 after，如果是按下回车键，mode 为 true
		 * 如果是因为编辑框失去焦点，mode 为 false */
		bool afterIsReturn;
		unsigned row, column;
		ctlSingleLabel* ctrl;
		//可以在 before 中设置 edit 的样式等
		ctlSingleEdit* edit;
	};
#pragma warning(push)
#pragma warning(disable:4250)
	class ctlList : virtual public ctlRoot, 
		public IFont, public IBackground
	{
	public:
		struct columnInfo
		{
			unsigned index;
			unsigned width;
		};
		struct rowInfo
		{
			unsigned index;
			unsigned height;
			//这个控件不应该手动添加子控件
			ctlStatic* ctrl;
		};
		struct cellInfo
		{
			unsigned row, column;
			//这个控件可以拥有子控件
			ctlSingleLabel* ctrl;
		};
	public:
		static const ctlControlType uniqueType = ctlControlType::ctlList;
	public:
		~ctlList() { destroy(); }
		bool create(ctlRoot* parent, ctlRect rect, 
			const ctlStyleList& style = ctlStyleList(ctlStyleList::common));
	public:
		//获取所有行的总高度
		unsigned getRowHeight();
		//获取所有列的总宽度
		unsigned getColumnWidth();
		//获取总行数
		unsigned getRowNumber();
		//获取总列数
		unsigned getColumnNumber();
		//获取行信息
		rowInfo getRowInfo(unsigned index);
		//获取列信息
		columnInfo getColumnInfo(unsigned index);
		//获取单元格信息
		cellInfo getCellInfo(unsigned row, unsigned cell);
		//插入一行，height 为 0 则为默认
		bool insertRow(unsigned index, unsigned height);
		//插入多行
		bool insertRows(unsigned index, unsigned *height, unsigned number);
		//交换两行
		bool swapRow(unsigned a, unsigned b);
		//根据指定列的文字排序指定范围内的行
		bool sortRows(unsigned begin, unsigned end, unsigned column, 
			bool(*sortCompareFunction)(std::wstring::const_pointer, std::wstring::const_pointer));
		//插入一列
		bool insertColumn(unsigned index, unsigned width);
		//在末尾插入一行，如果 height 为 0，则自动设置
		bool appendRow(unsigned height);
		//在末尾插入一列
		bool appendColumn(unsigned width);
		//删除一行
		bool removeRow(unsigned index);
		//删除一列
		bool removeColumn(unsigned index);
		//设置一行的高度
		bool setRowHeight(unsigned index, unsigned height);
		//设置一列的宽度
		bool setColumnWidth(unsigned index, unsigned width);
		//获取选中的行（如果没有选中则 ctrl 为 nullptr）
		rowInfo getSelectedRow();
		/* 获取选中的单元格（如果没有选中则 ctrl 为 nullptr
		 * 如果设置为一行选中则返回那一行第一个单元格 */
		cellInfo getSelectedCell();
		//设置选中的行（单元格）
		bool setSelectedCell(unsigned row, unsigned column);
		//清除选中的信息
		void clearSelected();
		//查找指定控件是否是行控件（找不到返回 0xFFFFFFFF）
		unsigned findRowIndex(ctlStatic*);
	public:
		enum class keyAffect : unsigned {
			scroll, select, none };
		void setKeyAffect(keyAffect);
		keyAffect getKeyAffect();
	public:
		void setOverflowX(ctlOverflowScroll);
		void setOverflowY(ctlOverflowScroll);
		ctlOverflowScroll getOverflowX();
		ctlOverflowScroll getOverflowY();
		ctlScroll* getVerticalScroll();
		ctlScroll* getHorizontalScroll();
		void scrollToY(unsigned row);
		void scrollToX(unsigned column);
	public:
		//设置是能选中一行还是单元格
		bool isLineSelect();
		void setLineSelect(bool);
		//设置表头
		bool isHeaderEnabled();
		void setHeaderEnable(bool);
		//设置表头高度（0 为自动计算）
		unsigned getHeaderHeight();
		void setHeaderHeight(unsigned);
	public:
		ctlButton* getHeaderCtrl(unsigned index);
		ctlStatic* getHeader();
	public:
		bool isDoubleClickEdit();
		void setDoubleClickEdit(bool);
	public:
		virtual void setStyle(const ctlStyleBase&);
	protected:
		virtual void _redraw_(_ctlInterior::drawInfo*);
		virtual void _mouse_event_(ctlMouseEvent*);
		virtual void _position_event_(ctlPositionEvent*);
		virtual void _key_event_(ctlKeyEvent*);
		virtual std::vector<ctlRoot*>::const_pointer _get_redraw_begin(unsigned);
		virtual unsigned _get_redraw_end(unsigned);
		virtual std::vector<ctlRoot*>::const_pointer _get_event_begin(unsigned);
		virtual unsigned _get_event_end(unsigned);
		virtual unsigned _get_redraw_or_event_number();
	private:
		bool _list_send_event(
			decltype(ctlNotifyList::afterRemoveColumn), 
			ctlStatic*, unsigned index, unsigned*);
		unsigned _list_get_body_top();
		unsigned _list_get_body_width();
		unsigned _list_get_body_height();
		void _check_scroll(bool xf = false);
		void _check_position(int);
		void _check_line_position(bool);
		bool _list_is_cell_equal(unsigned, unsigned, const cellInfo&);
		std::pair<unsigned, unsigned> _list_map_point_to_pos(ctlPoint);
		ctlPoint _list_map_pos_to_point(unsigned pos);
		static void _list_row_click_handler(ctlRoot*, ctlMouseEvent*);
		static void _list_row_dbclick_handler(ctlRoot*, ctlMouseEvent*);
		void _list_set_row_default_style(unsigned row);
		void _list_set_row_style(unsigned row, unsigned column,
			ctlColor begin, ctlColor end, ctlColor text);
	private:
		std::vector<rowInfo> _list_row_info;
		std::vector<columnInfo> _list_column_info;
		ctlScroll _list_scroll_vertical, _list_scroll_horizontal;
		unsigned _list_total_height, _list_total_width;
		bool _list_is_line_selecte, _list_header_enable;
		bool _list_is_double_click_edit;
		cellInfo _list_select_cell_info;
		ctlOverflowScroll _list_overflow_x, _list_overflow_y;
		ctlRoot* _list_temp_pointer;
		ctlStatic _list_header;
		ctlSingleEdit _list_edit;
		keyAffect _list_key_affect;
	private:
		unsigned _list_top_pos;	
		unsigned _list_top_offset;
		unsigned _list_left_offset;
	};
#pragma warning(pop)
}

#endif